//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package bg_runner

import (
	"context"
	"fmt"
	"time"

	bg_runner_core "atomgit.com/openlinksaas-org/api-server/bg_runner/core"
	"atomgit.com/openlinksaas-org/api-server/bg_runner/tasks"
	"atomgit.com/openlinksaas-org/api-server/dao"
	"go.uber.org/zap"
)

var _taskTypeMap map[string]bg_runner_core.BackGroundTask

type _TaskChanItem struct {
	bgTaskId string
	bgTask   bg_runner_core.BackGroundTask
}

func StartBgRunner(poolSize int, logger *zap.Logger) {
	taskChan := make(chan *_TaskChanItem, 10)
	go runProducer(taskChan)
	for i := 0; i < poolSize; i++ {
		go runExector(taskChan, logger)
	}
}

func runProducer(taskChan chan<- *_TaskChanItem) {
	for {
		bgTaskItem, err := dao.BgTaskDao.GetNextTask(context.Background())
		if err != nil {
			time.Sleep(30 * time.Second)
		} else {
			if bgTaskItem.VisibleTimeStamp-bgTaskItem.TimeStamp > 24*3600*1000 {
				//重试1天没有成功
				dao.BgTaskDao.RemoveTask(context.Background(), bgTaskItem.BgTaskId)
			} else {
				bgTask, ok := convertBgTask(bgTaskItem.BgTaskType, []byte(bgTaskItem.BgTaskData))
				if ok {
					taskChan <- &_TaskChanItem{
						bgTaskId: bgTaskItem.BgTaskId,
						bgTask:   bgTask,
					}
				} else {
					dao.BgTaskDao.RemoveTask(context.Background(), bgTaskItem.BgTaskId)
				}
			}
		}

	}
}

func convertBgTask(taskType string, taskData []byte) (bg_runner_core.BackGroundTask, bool) {
	taskCls, ok := _taskTypeMap[taskType]
	if !ok {
		return nil, false
	}
	task, err := taskCls.NewInstance(taskData)
	if err != nil {
		fmt.Println(err, taskType, string(taskData))
		return nil, false
	}
	return task, true
}

func runExector(taskChan <-chan *_TaskChanItem, logger *zap.Logger) {
	for {
		taskChanItem := <-taskChan
		err := taskChanItem.bgTask.Execute(logger)
		if err == nil {
			dao.BgTaskDao.RemoveTask(context.Background(), taskChanItem.bgTaskId)
		} else {
			logger.Error("exec task failed", zap.String("taskType", taskChanItem.bgTask.TaskType()), zap.Error(err))
		}
	}
}

func init() {
	_taskTypeMap = map[string]bg_runner_core.BackGroundTask{}
	taskClsList := []bg_runner_core.BackGroundTask{
		&tasks.IssueDelayCheck{},
		&tasks.ProjectIssueDependCheck{},
		&tasks.ProjectIssueReOpenCheck{},
	}
	for _, taskCls := range taskClsList {
		_taskTypeMap[taskCls.TaskType()] = taskCls
	}
}
